//
// Created by denglibin on 19-4-11.
//

/**
 * 散布聚集io是一种可以在单次系统调用中操作多个缓冲区的io方法，
 * 可以将单个数据流的内容写到多个缓冲区，或者把单个数据流读到多个缓冲区中。
 * 这种方法的另一个名字是向量io。 相对的系统调用io可以称为线性io。
 *
 * #include <sys/uio.h>
    ssize_t readv (int fd, const struct iovec *iov,int count);

        readv()从fd读取count个segment到iov描述的缓冲区中。
        fd：文件描述符
        iov : 结构体数组，每个结构体描述一个独立缓冲区，称其为段（segment）
        count: 读取多少个段到缓冲区。

    ssize_t writev (int fd, const struct iovec *iov,int count);
        writev()从iov描述的缓冲区中读取count个段的数据并写入到fd中。


    除了操作多个缓冲区 外，readv和writevde的行为和read,write一样。
    一组segment的集合称为向量(vector).每个段描述了所要读写的缓冲区的地址和长度。
    readv()在处理下个缓冲区 之前会填满当前缓冲区的iov_len个字节。
    writev()在处理下个缓冲区之前，把当前缓冲区所有iov_len个字节数据输出。
    两个函数从iov[0]到iov[1]，直到iov[count-1]来顺序处理这些段。

   返回值：
    操作成功时，readv()和writev()分别返回读写的字节数。返回值应该等于所有iov_len的和。
    出错时返回-1，并且设置errno.

    错误： 如果iov_len的和大于了SSIZE_MAX 则不做处理返回-1，errno设置EINVAL
           count必须大于0小于IOV_MAX(limits.h中定义)。linux中IOV_MAX通常是1024
           如果count为0返回0,如果count大于IOV_MAX，不做处理，返回-1,errno设置为EINVAL

    优化count：
        在向量io操作中，内核必须申请内核数据结构来表示每个段。通常，申请是基于count的大小动态进行的。
        出于优化的目的，如果count足够小的话，内核会在栈上创建 几个段，通过动态内存分配得到性能上的一些提升。
        这个阀值一般是8.
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/uio.h>
#include <unistd.h>
#define  PATH "/home/denglibin/open.txt"

//测试writev()
int writev_(){
    struct iovec iov[3];//3个缓冲区（segment）
    ssize_t nr;
    int fd, i;
    char * s[] = {"The term buccaneer comes from the word boucan.\n",
                  "A boucan is a wooden frame used for cooking meat.\n",
                  "Buccaneer is the West Indies name for a pirate.\n"};

    fd = open(PATH, O_WRONLY | O_APPEND);
    if(fd == -1){
        perror("open");
        return -1;
    }
    //填充结构体
    for(i = 0; i < 3; i++){
        iov[i].iov_base = s[i];
        iov[i].iov_len = strlen(s[i]);
    }
    nr = writev(fd, iov, 3);
    if(nr == -1){
        perror("writev");
        close(fd);
        return -1;
    }
    printf("写入字节数：%zd\n", nr);
    if(close(fd)){
        perror("close");
        return -1;
    }
    return 0;
}

//测试readv
int readv_(){
    //定义三个缓冲区
    char foo[47], bar[50], baz[50];
    //结构体数组
    struct iovec iov[3];
    ssize_t nr;
    int fd, i;
    fd = open (PATH, O_RDONLY);
    if (fd == -1) {
        perror ("open");
        return 1;
    }
    //设置结构体
    iov[0].iov_base = foo;
    iov[0].iov_len = sizeof (foo);

    iov[1].iov_base = bar;
    iov[1].iov_len = sizeof (bar);

    iov[2].iov_base = baz;
    iov[2].iov_len = sizeof (baz);
    nr = readv (fd, iov, 3);
    printf("读取字节数:%zd\n", nr);
    if(nr == -1){
        perror("readv");
        close(fd);
        return 1;
    }
    for(i = 0; i < 3; i++){
        printf("%d : %s",i,iov[i].iov_base);
    }
    if(close(fd)){
        perror("close");
        return 1;
    }
    return 0;

}

static int main_(void){

    //writev_();
    readv_();
    return 0;
}

